
using System;
using System.ComponentModel;
using System.Windows;
using System.Collections;

using needle.UI.Controls.Month;
using needle.UI.Controls.Day;

namespace needle.Appointments {

    #region Delegates

    public delegate void AppointmentEventHandler(object sender, EventArgs e);

    #endregion


    /// <summary>
    /// Represents a collection of DateItem objects
    /// </summary>
    public class AppointmentCollection : CollectionBase {
        #region Class Data

        /// <summary>
        /// The Calendar that owns this DateItemCollection
        /// </summary>
        private MonthCalendar owner;

        #endregion

        #region Events

        public event AppointmentEventHandler DateItemModified;

        #endregion

        #region Constructor

        public AppointmentCollection(MonthCalendar owner)
            : base() {
            if (owner == null)
                throw new ArgumentNullException("owner");

            this.owner = owner;
        }

        public AppointmentCollection(MonthCalendar owner, AppointmentCollection dateItems)
            : this(owner) {
            this.Add(dateItems);
        }

        #endregion

        #region Methods

        public void ModifiedEvent() {
            if (DateItemModified != null)
                DateItemModified(this, new EventArgs());
        }

        public void Add(Appointment value) {
            int index;
            if (value == null)
                throw new ArgumentNullException("value");

            if ((MonthCalendar)value.Calendar == null)
                value.Calendar = this.owner;

            index = this.IndexOf(value);
            if (index == -1)
                this.List.Add(value);
            else
                this.List[index] = value;
        }

        public void AddRange(Appointment[] dateItems) {
            if (dateItems == null)
                throw new ArgumentNullException("dateItems");

            for (int i = 0; i < dateItems.Length; i++) {
                dateItems[i].Calendar = owner;
                this.Add(dateItems[i]);
            }
        }

        public void Add(AppointmentCollection dateItems) {
            if (dateItems == null)
                throw new ArgumentNullException("dateItems");

            for (int i = 0; i < dateItems.Count; i++) {
                this.Add(dateItems[i]);
            }
        }

        public new void Clear() {
            while (this.Count > 0) {
                this.RemoveAt(0);
            }
        }

        public bool Contains(Appointment dateItem) {
            if (dateItem == null)
                throw new ArgumentNullException("dateItem");

            return (this.IndexOf(dateItem) != -1);
        }

        public int IndexOf(DateTime date) {
            Appointment[] d;

            d = AppointmentInfo(date);
            if (d.Length > 0)
                return d[0].Index;
            else
                return -1;
        }

        public Appointment[] AppointmentInfo(DateTime dt) {
            Appointment[] ret = new Appointment[0];
            ret.Initialize();
            for (int i = 0; i < this.Count; i++) {
                if (((this[i].Date <= dt) && (this[i].Range >= dt))) {
                    switch (this[i].Recurrence) {
                        case mcDayInfoRecurrence.None: {
                                if (this[i].Date.ToShortDateString() == dt.ToShortDateString()) {
                                    this[i].Index = i;
                                    ret = AddInfo(this[i], ret);
                                }
                                break;
                            }
                        case mcDayInfoRecurrence.Appointment: {
                                if (this[i].Date.ToShortDateString() == dt.ToShortDateString()) {
                                    this[i].Index = i;
                                    ret = AddInfo(this[i], ret);
                                }
                                break;
                            }
                        case mcDayInfoRecurrence.Appointments: {
                                if (this[i].Date.ToShortDateString() == dt.ToShortDateString()) {
                                    this[i].Index = i;
                                    ret = AddInfo(this[i], ret);
                                }
                                break;
                            }
                        case mcDayInfoRecurrence.Daily: {
                                this[i].Index = i;
                                ret = AddInfo(this[i], ret);
                                break;
                            }
                        case mcDayInfoRecurrence.Weekly: {
                                if ((this[i].Date.DayOfWeek == dt.DayOfWeek)) {
                                    this[i].Index = i;
                                    ret = AddInfo(this[i], ret);
                                }
                                break;
                            }
                        case mcDayInfoRecurrence.Monthly: {
                                if ((this[i].Date.Day == dt.Day)) {
                                    this[i].Index = i;
                                    ret = AddInfo(this[i], ret);
                                }
                                break;
                            }
                        case mcDayInfoRecurrence.Yearly: {
                                if (this[i].Date.ToShortDateString().Substring(5) ==
                                    dt.ToShortDateString().Substring(5)) {
                                    this[i].Index = i;
                                    ret = AddInfo(this[i], ret);
                                }
                                break;
                            }
                    }

                }
            }
            return ret;
        }

        public Appointment[] AddInfo(Appointment dt, Appointment[] old) {
            int l = old.Length;
            int i;
            Appointment[] n = new Appointment[l + 1];
            n.Initialize();
            for (i = 0; i < l; i++) {
                n[i] = old[i];
            }
            n[i] = dt;
            return n;
        }

        public int IndexOf(Appointment dateItem) {
            if (dateItem == null)
                throw new ArgumentNullException("dateItem");

            for (int i = 0; i < this.Count; i++) {
                if (this[i] == dateItem) {
                    return i;
                }
            }

            return -1;
        }

        public void Remove(Appointment value) {
            if (value == null)
                throw new ArgumentNullException("value");

            this.List.Remove(value);

        }

        public new void RemoveAt(int index) {
            this.Remove(this[index]);
        }

        public void Move(Appointment value, int index) {
            if (value == null)
                throw new ArgumentNullException("value");

            if (index < 0) {
                index = 0;
            }
            else if (index > this.Count) {
                index = this.Count;
            }

            if (!this.Contains(value) || this.IndexOf(value) == index) {
                return;
            }

            this.List.Remove(value);

            if (index > this.Count) {
                this.List.Add(value);
            }
            else {
                this.List.Insert(index, value);
            }

        }

        public void MoveToTop(Appointment value) {
            this.Move(value, 0);
        }


        public void MoveToBottom(Appointment value) {
            this.Move(value, this.Count);
        }

        #endregion

        #region Properties

        public virtual Appointment this[int index] {
            get {
                return this.List[index] as Appointment;
            }
        }

        #endregion

    }

    public class DaysCollection : CollectionBase {

        #region Class Data

        /// <summary>
        /// The Calendar that owns this DateItemCollection
        /// </summary>
        private DayCalendar owner;

        #endregion

        #region Events

        public event AppointmentEventHandler DateItemModified;

        #endregion

        #region Constructor

        public DaysCollection(DayCalendar owner)
            : base() {
            if (owner == null)
                throw new ArgumentNullException("owner");

            this.owner = owner;
        }

        public DaysCollection(DayCalendar owner, DaysCollection dateItems)
            : this(owner) {
            this.Add(dateItems);
        }

        #endregion

        #region Methods

        public void ModifiedEvent() {
            if (DateItemModified != null)
                DateItemModified(this, new EventArgs());
        }

        public void Add(DateTime value) {
            int index;
            if (value == null)
                throw new ArgumentNullException("value");

            //if ((MonthCalendar)value.Day == null)
            //    value.Day = this.owner;

            index = this.IndexOf(value);
            if (index == -1)
                this.List.Add(value);
            else
                this.List[index] = value;
        }

        public void AddRange(DateTime[] dateItems) {
            if (dateItems == null)
                throw new ArgumentNullException("dateItems");

            for (int i = 0; i < dateItems.Length; i++) {
                this.Add(dateItems[i]);
            }
        }

        public void Add(DaysCollection dateItems) {
            if (dateItems == null)
                throw new ArgumentNullException("dateItems");

            for (int i = 0; i < dateItems.Count; i++) {
                this.Add(dateItems[i]);
            }
            this.InnerList.Sort();  
        }

        public new void Clear() {
            while (this.Count > 0) {
                this.RemoveAt(0);
            }
        }

        public bool Contains(DateTime dateItem) {
            if (dateItem == null)
                throw new ArgumentNullException("dateItem");

            return (this.IndexOf(dateItem) != -1);
        }

        //public int IndexOf(DateTime date) {
        //    Appointment[] d;

        //    d = DateInfo(date);
        //    if (d.Length > 0)
        //        return d[0].Index;
        //    else
        //        return -1;
        //}

        public DateTime[] DateInfo(DateTime dt) {
            DateTime[] ret = new DateTime[0];
            ret.Initialize();
            for (int i = 0; i < this.Count; i++) {
                if (((this[i].Date <= dt) && (this[i].Date >= dt))) {

                    if (this[i].Date.ToShortDateString() == dt.ToShortDateString()) {
                        ret = AddInfo(this[i], ret);
                    }

                    break;

                }
            }
            return ret;
        }

        public DateTime[] AddInfo(DateTime dt, DateTime[] old) {
            int l = old.Length;
            int i;
            DateTime[] n = new DateTime[l + 1];
            n.Initialize();
            for (i = 0; i < l; i++) {
                n[i] = old[i];
            }
            n[i] = dt;
            return n;
        }

        public int IndexOf(DateTime dateItem) {
            if (dateItem == null)
                throw new ArgumentNullException("dateItem");

            for (int i = 0; i < this.Count; i++) {
                if (this[i] == dateItem) {
                    return i;
                }
            }

            return -1;
        }

        public void Remove(DateTime value) {
            if (value == null)
                throw new ArgumentNullException("value");

            this.List.Remove(value);

        }

        public new void RemoveAt(int index) {
            this.Remove(this[index]);
        }

        public void Move(DateTime value, int index) {
            if (value == null)
                throw new ArgumentNullException("value");

            if (index < 0) {
                index = 0;
            }
            else if (index > this.Count) {
                index = this.Count;
            }

            if (!this.Contains(value) || this.IndexOf(value) == index) {
                return;
            }

            this.List.Remove(value);

            if (index > this.Count) {
                this.List.Add(value);
            }
            else {
                this.List.Insert(index, value);
            }

        }

        public void MoveToTop(DateTime value) {
            this.Move(value, 0);
        }


        public void MoveToBottom(DateTime value) {
            this.Move(value, this.Count);
        }

        #endregion

        #region Properties

        public virtual DateTime this[int index] {
            get {
                return (DateTime)this.List[index];
            }
        }

        #endregion

    }

}
